/*
A sample shader for use with "tinted_occlusion_scene.mi".
The scene file is in Templates->mi
Malcolm Kesson: Jan 2007
Modified by Chip Collier: Dec 2008
*/

#include "shader.h"

inline float clamp(float x, float a, float b)
{
    return x < a ? a : (x > b ? b : x);
}

struct tinted_occlusion {
	miBoolean custom; 	/* default false */
	miUint samples; 	/* default [128] */
	miColor tint; 		/* default [1 1 1]  */
};


DLLEXPORT
int tinted_occlusion_version(void) {return(1);}

DLLEXPORT
miBoolean tinted_occlusion(
    miColor     *result,
    miState     *state,
    struct tinted_occlusion *params)
{
	miBoolean custom = *mi_eval_boolean(&params->custom);
	miUint samples = *mi_eval_integer(&params->samples);
    miColor *tint = mi_eval_color(&params->tint);
	miScalar ambient_exposure = 0.0;

	if (custom)
	{
		// Use the method provided by Mr. Kesson
		miVector trace_direction;
    	int object_hit = 0, sample_number = 0;
	    double sample[3], hit_fraction, ambient_exposure;
	
	    while (mi_sample(sample, &sample_number, state, 3, &samples)) {
			mi_reflection_dir_diffuse_x(&trace_direction, state, sample);
			if (mi_trace_probe(state, &trace_direction, &state->point))
		    	object_hit++;
	    	}
	    hit_fraction = ((double)object_hit / (double)samples);
	    ambient_exposure = 1.0 - hit_fraction;
		//result->r = tint->r * ambient_exposure;
		//result->g = tint->g * ambient_exposure;
		//result->b = tint->b * ambient_exposure;
	}
	else
	{
		// Testing the new 3.6 ambient occlusion call
		ambient_exposure = (1.0 - mi_ambient_occlusion(state, NULL, NULL));
		//result->r = clamp(tint->r - ambient_exposure, 0.0, 1.0);
		//result->g = clamp(tint->g - ambient_exposure, 0.0, 1.0);
		//result->b = clamp(tint->b - ambient_exposure, 0.0, 1.0);
	}
	
	if (ambient_exposure < 0.0)
	{
		ambient_exposure = 0.0;
	}
	
	result->r = tint->r * ambient_exposure;
	result->g = tint->g * ambient_exposure;
	result->b = tint->b * ambient_exposure;
	
    result->a = 1.0;
    return miTRUE;
}
